package com.beidu.lottery.call.service.portal.component;

import com.github.pagehelper.PageInfo;
import com.beidu.lottery.call.entity.query.PortalGroupOptionQuery;
import com.beidu.lottery.call.entity.query.PortalOptionQuery;
import com.beidu.lottery.call.entity.vo.PortalOptionVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 投票组件
 *
 * @author 北渡
 */
@Component
@SuppressWarnings({"rawtypes", "unchecked"})
public class VoteComponent {

    @Resource
    private RedisTemplate redisTemplate;

    private HashOperations hashOperations;

    @PostConstruct
    public void init() {
        hashOperations = redisTemplate.opsForHash();
    }

    /**
     * 在指定活动中，根据选项id增加自增票数
     *
     * @param key      hotspot:{活动id}:{分组id}:options
     * @param optionId 选项id
     * @param delta    递增值
     * @return 增加后的值
     * @author 北渡
     */
    public long increment(String key, Integer optionId, long delta) {
        return hashOperations.increment(key + ":votes", Integer.toString(optionId), delta);
    }

    /**
     * 在指定活动中，根据选项id增加递减票数（回滚）
     *
     * @param key      hotspot:{活动id}:{分组id}:options
     * @param optionId 选项id
     * @param delta    递减值
     * @return 减少后的值
     * @author 北渡
     */
    @SuppressWarnings({"all", "忽略未使用返回值"})
    public long decrement(String key, Integer optionId, long delta) {
        return hashOperations.increment(key + ":votes", Integer.toString(optionId), -delta);
    }

    /**
     * 缓存投票选项列表
     *
     * @param list 投票选项列表
     * @author 北渡
     */
    public void cacheVoteOptions(String key, List<PortalOptionVO> list) {
        // 缓存选项列表（Hash结构）
        hashOperations.putAll(key, list.stream().collect(Collectors.toMap(PortalOptionVO::getOptionId, v -> v, (a, b) -> b)));
        // 缓存选项票数（Hash结构）
        hashOperations.putAll(key + ":votes", list.stream().collect(Collectors.toMap(PortalOptionVO::getOptionId, PortalOptionVO::getVotes, (a, b) -> b)));
    }

    /**
     * 匹配排序方式
     *
     * @param type 0:编号正序, 1:人气倒序
     * @author 北渡
     */
    private Comparator<PortalOptionVO> matchOrderType(Integer type) {
        return type == 0 ? Comparator.comparing(PortalOptionVO::getOptionCode) : Comparator.comparing(PortalOptionVO::getVotes).reversed();
    }

    /**
     * 投票选项分页
     *
     * @param key   键
     * @param param 分页查询条件
     * @return 投票选项列表
     * @author 北渡
     */
    public PageInfo<PortalOptionVO> pageVoteOption(String key, PortalGroupOptionQuery param) {
        // 选项缓存
        Map<String, PortalOptionVO> optionMap = hashOperations.entries(key);
        // 票数缓存
        Map<String, Integer> votesMap = hashOperations.entries(key + ":votes");
        // 组装List（条件筛选）
        List<PortalOptionVO> result = optionMap.values().stream()
                // 模糊匹配
                .filter(option -> StringUtils.isEmpty(param.getKeyword()) ||
                        option.getOptionCode().contains(param.getKeyword()) ||
                        option.getAuthorName().contains(param.getKeyword()) ||
                        option.getOptionName().contains(param.getKeyword()))
                // 关联票数
                .peek(option -> option.setVotes(votesMap.get(option.getOptionId())))
                // 排序（0:编号正序, 1:人气倒序）
                .sorted(this.matchOrderType(param.getOrderBy())).collect(Collectors.toList());
        // 判断列表大小是否足够进行分页
        if (result.size() <= (param.getPageNum() - 1) * param.getPageSize()) {
            return new PageInfo<>();
        }
        // 计算分页的起始索引和结束索引
        int startIndex = (param.getPageNum() - 1) * param.getPageSize();
        int endIndex = Math.min(startIndex + param.getPageSize(), result.size());
        // 组装分页对象
        PageInfo<PortalOptionVO> pageInfo = new PageInfo<>();
        pageInfo.setTotal(result.size());
        pageInfo.setList(result.subList(startIndex, endIndex));// 分页
        return pageInfo;
    }

    /**
     * 投票选项详情
     *
     * @param key   键
     * @param param 分页查询条件
     * @return 投票选项列表
     * @author 北渡
     */
    public PortalOptionVO queryVoteOption(String key, PortalOptionQuery param) {
        // 选项缓存
        Map<String, PortalOptionVO> optionMap = hashOperations.entries(key);
        // 票数缓存
        Map<String, Integer> votesMap = hashOperations.entries(key + ":votes");
        // 根据选项ID匹配选项
        PortalOptionVO option = optionMap.get(param.getOptionId());
        // 关联票数
        option.setVotes(votesMap.get(option.getOptionId()));
        return option;
    }

}